/**
  ******************************************************************************
  * @file    usb_hcd_int.c
  * @author  MCD Application Team
  * @version V2.1.0
  * @date    19-March-2012
  * @brief   Host driver interrupt subroutines
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "usb_core.h"
#include "usb_defines.h"
#include "usb_hcd_int.h"

#if defined   (__CC_ARM) /*!< ARM Compiler */
#pragma O0
#elif defined (__GNUC__) /*!< GNU Compiler */
#pragma GCC optimize ("O0")
#elif defined  (__TASKING__) /*!< TASKING Compiler */
#pragma optimize=0

#endif /* __CC_ARM */

/** @addtogroup USB_OTG_DRIVER
* @{
*/

/** @defgroup USB_HCD_INT
* @brief This file contains the interrupt subroutines for the Host mode.
* @{
*/


/** @defgroup USB_HCD_INT_Private_Defines
* @{
*/
/**
* @}
*/


/** @defgroup USB_HCD_INT_Private_TypesDefinitions
* @{
*/
/**
* @}
*/



/** @defgroup USB_HCD_INT_Private_Macros
* @{
*/
/**
* @}
*/


/** @defgroup USB_HCD_INT_Private_Variables
* @{
*/
/**
* @}
*/


/** @defgroup USB_HCD_INT_Private_FunctionPrototypes
* @{
*/

static uint32_t USB_OTG_USBH_handle_sof_ISR(USB_OTG_CORE_HANDLE *pdev);
static uint32_t USB_OTG_USBH_handle_port_ISR(USB_OTG_CORE_HANDLE *pdev);
static uint32_t USB_OTG_USBH_handle_hc_ISR(USB_OTG_CORE_HANDLE *pdev);
static uint32_t USB_OTG_USBH_handle_hc_n_In_ISR(USB_OTG_CORE_HANDLE *pdev,
        uint32_t num);
static uint32_t USB_OTG_USBH_handle_hc_n_Out_ISR(USB_OTG_CORE_HANDLE *pdev,
        uint32_t num);
static uint32_t USB_OTG_USBH_handle_rx_qlvl_ISR(USB_OTG_CORE_HANDLE *pdev);
static uint32_t USB_OTG_USBH_handle_nptxfempty_ISR(USB_OTG_CORE_HANDLE *pdev);
static uint32_t USB_OTG_USBH_handle_ptxfempty_ISR(USB_OTG_CORE_HANDLE *pdev);
static uint32_t USB_OTG_USBH_handle_Disconnect_ISR(USB_OTG_CORE_HANDLE *pdev);
static uint32_t USB_OTG_USBH_handle_IncompletePeriodicXfer_ISR(USB_OTG_CORE_HANDLE *pdev);

/**
* @}
*/


/** @defgroup USB_HCD_INT_Private_Functions
* @{
*/

/**
* @brief  HOST_Handle_ISR
*         This function handles all USB Host Interrupts
* @param  pdev: Selected device
* @retval status
*/

uint32_t USBH_OTG_ISR_Handler(USB_OTG_CORE_HANDLE *pdev)
{
    USB_OTG_GINTSTS_TypeDef  gintsts;
    uint32_t retval = 0;
    gintsts.d32 = 0;

    /* Check if HOST Mode */
    if(USB_OTG_IsHostMode(pdev))
    {
        gintsts.d32 = USB_OTG_ReadCoreItr(pdev);

        if(!gintsts.d32)
        {
            return 0;
        }

        if(gintsts.b.sofintr)
        {
            retval |= USB_OTG_USBH_handle_sof_ISR(pdev);
        }

        if(gintsts.b.rxstsqlvl)
        {
            retval |= USB_OTG_USBH_handle_rx_qlvl_ISR(pdev);
        }

        if(gintsts.b.nptxfempty)
        {
            retval |= USB_OTG_USBH_handle_nptxfempty_ISR(pdev);
        }

        if(gintsts.b.ptxfempty)
        {
            retval |= USB_OTG_USBH_handle_ptxfempty_ISR(pdev);
        }

        if(gintsts.b.hcintr)
        {
            retval |= USB_OTG_USBH_handle_hc_ISR(pdev);
        }

        if(gintsts.b.portintr)
        {
            retval |= USB_OTG_USBH_handle_port_ISR(pdev);
        }

        if(gintsts.b.disconnect)
        {
            retval |= USB_OTG_USBH_handle_Disconnect_ISR(pdev);
        }

        if(gintsts.b.incomplisoout)
        {
            retval |= USB_OTG_USBH_handle_IncompletePeriodicXfer_ISR(pdev);
        }
    }

    return retval;
}

/**
* @brief  USB_OTG_USBH_handle_hc_ISR
*         This function indicates that one or more host channels has a pending
* @param  pdev: Selected device
* @retval status
*/
static uint32_t USB_OTG_USBH_handle_hc_ISR(USB_OTG_CORE_HANDLE *pdev)
{
    USB_OTG_HAINT_TypeDef        haint;
    USB_OTG_HCCHAR_TypeDef       hcchar;
    uint32_t i = 0;
    uint32_t retval = 0;
    /* Clear appropriate bits in HCINTn to clear the interrupt bit in
    * GINTSTS */
    haint.d32 = USB_OTG_ReadHostAllChannels_intr(pdev);

    for(i = 0; i < pdev->cfg.host_channels ; i++)
    {
        if(haint.b.chint & (1 << i))
        {
            hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[i]->HCCHAR);

            if(hcchar.b.epdir)
            {
                retval |= USB_OTG_USBH_handle_hc_n_In_ISR(pdev, i);
            }
            else
            {
                retval |=  USB_OTG_USBH_handle_hc_n_Out_ISR(pdev, i);
            }
        }
    }

    return retval;
}

/**
* @brief  USB_OTG_otg_hcd_handle_sof_intr
*         Handles the start-of-frame interrupt in host mode.
* @param  pdev: Selected device
* @retval status
*/
static uint32_t USB_OTG_USBH_handle_sof_ISR(USB_OTG_CORE_HANDLE *pdev)
{
    USB_OTG_GINTSTS_TypeDef      gintsts;
    gintsts.d32 = 0;
    USBH_HCD_INT_fops->SOF(pdev);
    /* Clear interrupt */
    gintsts.b.sofintr = 1;
    USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32);
    return 1;
}

/**
* @brief  USB_OTG_USBH_handle_Disconnect_ISR
*         Handles disconnect event.
* @param  pdev: Selected device
* @retval status
*/
static uint32_t USB_OTG_USBH_handle_Disconnect_ISR(USB_OTG_CORE_HANDLE *pdev)
{
    USB_OTG_GINTSTS_TypeDef      gintsts;
    gintsts.d32 = 0;
    USBH_HCD_INT_fops->DevDisconnected(pdev);
    /* Clear interrupt */
    gintsts.b.disconnect = 1;
    USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32);
    return 1;
}
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma optimize = none
#endif /* __CC_ARM */
/**
* @brief  USB_OTG_USBH_handle_nptxfempty_ISR
*         Handles non periodic tx fifo empty.
* @param  pdev: Selected device
* @retval status
*/
static uint32_t USB_OTG_USBH_handle_nptxfempty_ISR(USB_OTG_CORE_HANDLE *pdev)
{
    USB_OTG_GINTMSK_TypeDef      intmsk;
    USB_OTG_HNPTXSTS_TypeDef     hnptxsts;
    uint16_t                     len_words, len;
    hnptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS);
    len_words = (pdev->host.hc[hnptxsts.b.nptxqtop.chnum].xfer_len + 3) / 4;

    while((hnptxsts.b.nptxfspcavail > len_words) &&
            (pdev->host.hc[hnptxsts.b.nptxqtop.chnum].xfer_len != 0))
    {
        len = hnptxsts.b.nptxfspcavail * 4;

        if(len > pdev->host.hc[hnptxsts.b.nptxqtop.chnum].xfer_len)
        {
            /* Last packet */
            len = pdev->host.hc[hnptxsts.b.nptxqtop.chnum].xfer_len;
            intmsk.d32 = 0;
            intmsk.b.nptxfempty = 1;
            USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, 0);
        }

        len_words = (pdev->host.hc[hnptxsts.b.nptxqtop.chnum].xfer_len + 3) / 4;
        USB_OTG_WritePacket(pdev, pdev->host.hc[hnptxsts.b.nptxqtop.chnum].xfer_buff, hnptxsts.b.nptxqtop.chnum, len);
        pdev->host.hc[hnptxsts.b.nptxqtop.chnum].xfer_buff  += len;
        pdev->host.hc[hnptxsts.b.nptxqtop.chnum].xfer_len   -= len;
        pdev->host.hc[hnptxsts.b.nptxqtop.chnum].xfer_count  += len;
        hnptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->HNPTXSTS);
    }

    return 1;
}
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma optimize = none
#endif /* __CC_ARM */
/**
* @brief  USB_OTG_USBH_handle_ptxfempty_ISR
*         Handles periodic tx fifo empty
* @param  pdev: Selected device
* @retval status
*/
static uint32_t USB_OTG_USBH_handle_ptxfempty_ISR(USB_OTG_CORE_HANDLE *pdev)
{
    USB_OTG_GINTMSK_TypeDef      intmsk;
    USB_OTG_HPTXSTS_TypeDef      hptxsts;
    uint16_t                     len_words, len;
    hptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HPTXSTS);
    len_words = (pdev->host.hc[hptxsts.b.ptxqtop.chnum].xfer_len + 3) / 4;

    while((hptxsts.b.ptxfspcavail > len_words) &&
            (pdev->host.hc[hptxsts.b.ptxqtop.chnum].xfer_len != 0))
    {
        len = hptxsts.b.ptxfspcavail * 4;

        if(len > pdev->host.hc[hptxsts.b.ptxqtop.chnum].xfer_len)
        {
            len = pdev->host.hc[hptxsts.b.ptxqtop.chnum].xfer_len;
            /* Last packet */
            intmsk.d32 = 0;
            intmsk.b.ptxfempty = 1;
            USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, 0);
        }

        len_words = (pdev->host.hc[hptxsts.b.ptxqtop.chnum].xfer_len + 3) / 4;
        USB_OTG_WritePacket(pdev, pdev->host.hc[hptxsts.b.ptxqtop.chnum].xfer_buff, hptxsts.b.ptxqtop.chnum, len);
        pdev->host.hc[hptxsts.b.ptxqtop.chnum].xfer_buff  += len;
        pdev->host.hc[hptxsts.b.ptxqtop.chnum].xfer_len   -= len;
        pdev->host.hc[hptxsts.b.ptxqtop.chnum].xfer_count  += len;
        hptxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HPTXSTS);
    }

    return 1;
}

/**
* @brief  USB_OTG_USBH_handle_port_ISR
*         This function determines which interrupt conditions have occurred
* @param  pdev: Selected device
* @retval status
*/
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma optimize = none
#endif /* __CC_ARM */
static uint32_t USB_OTG_USBH_handle_port_ISR(USB_OTG_CORE_HANDLE *pdev)
{
    USB_OTG_HPRT0_TypeDef  hprt0;
    USB_OTG_HPRT0_TypeDef  hprt0_dup;
    USB_OTG_HCFG_TypeDef   hcfg;
    uint32_t do_reset = 0;
    uint32_t retval = 0;
    hcfg.d32 = 0;
    hprt0.d32 = 0;
    hprt0_dup.d32 = 0;
    hprt0.d32 = USB_OTG_READ_REG32(pdev->regs.HPRT0);
    hprt0_dup.d32 = USB_OTG_READ_REG32(pdev->regs.HPRT0);
    /* Clear the interrupt bits in GINTSTS */
    hprt0_dup.b.prtena = 0;
    hprt0_dup.b.prtconndet = 0;
    hprt0_dup.b.prtenchng = 0;
    hprt0_dup.b.prtovrcurrchng = 0;

    /* Port Connect Detected */
    if(hprt0.b.prtconndet)
    {
        hprt0_dup.b.prtconndet = 1;
        USBH_HCD_INT_fops->DevConnected(pdev);
        retval |= 1;
    }

    /* Port Enable Changed */
    if(hprt0.b.prtenchng)
    {
        hprt0_dup.b.prtenchng = 1;

        if(hprt0.b.prtena == 1)
        {
            USBH_HCD_INT_fops->DevConnected(pdev);

            if((hprt0.b.prtspd == HPRT0_PRTSPD_LOW_SPEED) ||
                    (hprt0.b.prtspd == HPRT0_PRTSPD_FULL_SPEED))
            {
                hcfg.d32 = USB_OTG_READ_REG32(&pdev->regs.HREGS->HCFG);

                if(hprt0.b.prtspd == HPRT0_PRTSPD_LOW_SPEED)
                {
                    USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HFIR, 6000);

                    if(hcfg.b.fslspclksel != HCFG_6_MHZ)
                    {
                        if(pdev->cfg.phy_itface  == USB_OTG_EMBEDDED_PHY)
                        {
                            USB_OTG_InitFSLSPClkSel(pdev, HCFG_6_MHZ);
                        }

                        do_reset = 1;
                    }
                }
                else
                {
                    USB_OTG_WRITE_REG32(&pdev->regs.HREGS->HFIR, 48000);

                    if(hcfg.b.fslspclksel != HCFG_48_MHZ)
                    {
                        USB_OTG_InitFSLSPClkSel(pdev, HCFG_48_MHZ);
                        do_reset = 1;
                    }
                }
            }
            else
            {
                do_reset = 1;
            }
        }
    }

    /* Overcurrent Change Interrupt */
    if(hprt0.b.prtovrcurrchng)
    {
        hprt0_dup.b.prtovrcurrchng = 1;
        retval |= 1;
    }

    if(do_reset)
    {
        USB_OTG_ResetPort(pdev);
    }

    /* Clear Port Interrupts */
    USB_OTG_WRITE_REG32(pdev->regs.HPRT0, hprt0_dup.d32);
    return retval;
}
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma optimize = none
#endif /* __CC_ARM */
/**
* @brief  USB_OTG_USBH_handle_hc_n_Out_ISR
*         Handles interrupt for a specific Host Channel
* @param  pdev: Selected device
* @param  hc_num: Channel number
* @retval status
*/
uint32_t USB_OTG_USBH_handle_hc_n_Out_ISR(USB_OTG_CORE_HANDLE *pdev, uint32_t num)
{
    USB_OTG_HCINTn_TypeDef     hcint;
    USB_OTG_HCINTMSK_TypeDef  hcintmsk;
    USB_OTG_HC_REGS *hcreg;
    USB_OTG_HCCHAR_TypeDef     hcchar;
    hcreg = pdev->regs.HC_REGS[num];
    hcint.d32 = USB_OTG_READ_REG32(&hcreg->HCINT);
    hcintmsk.d32 = USB_OTG_READ_REG32(&hcreg->HCINTMSK);
    hcint.d32 = hcint.d32 & hcintmsk.d32;
    hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[num]->HCCHAR);

    if(hcint.b.ahberr)
    {
        CLEAR_HC_INT(hcreg, ahberr);
        UNMASK_HOST_INT_CHH(num);
    }
    else if(hcint.b.ack)
    {
        CLEAR_HC_INT(hcreg, ack);
    }
    else if(hcint.b.frmovrun)
    {
        UNMASK_HOST_INT_CHH(num);
        USB_OTG_HC_Halt(pdev, num);
        CLEAR_HC_INT(hcreg, frmovrun);
    }
    else if(hcint.b.xfercompl)
    {
        pdev->host.ErrCnt[num] = 0;
        UNMASK_HOST_INT_CHH(num);
        USB_OTG_HC_Halt(pdev, num);
        CLEAR_HC_INT(hcreg, xfercompl);
        pdev->host.HC_Status[num] = HC_XFRC;
    }
    else if(hcint.b.stall)
    {
        CLEAR_HC_INT(hcreg, stall);
        UNMASK_HOST_INT_CHH(num);
        USB_OTG_HC_Halt(pdev, num);
        pdev->host.HC_Status[num] = HC_STALL;
    }
    else if(hcint.b.nak)
    {
        pdev->host.ErrCnt[num] = 0;
        UNMASK_HOST_INT_CHH(num);
        USB_OTG_HC_Halt(pdev, num);
        CLEAR_HC_INT(hcreg, nak);
        pdev->host.HC_Status[num] = HC_NAK;
    }
    else if(hcint.b.xacterr)
    {
        UNMASK_HOST_INT_CHH(num);
        USB_OTG_HC_Halt(pdev, num);
        pdev->host.ErrCnt[num] ++;
        pdev->host.HC_Status[num] = HC_XACTERR;
        CLEAR_HC_INT(hcreg, xacterr);
    }
    else if(hcint.b.nyet)
    {
        pdev->host.ErrCnt[num] = 0;
        UNMASK_HOST_INT_CHH(num);
        USB_OTG_HC_Halt(pdev, num);
        CLEAR_HC_INT(hcreg, nyet);
        pdev->host.HC_Status[num] = HC_NYET;
    }
    else if(hcint.b.datatglerr)
    {
        UNMASK_HOST_INT_CHH(num);
        USB_OTG_HC_Halt(pdev, num);
        CLEAR_HC_INT(hcreg, nak);
        pdev->host.HC_Status[num] = HC_DATATGLERR;
        CLEAR_HC_INT(hcreg, datatglerr);
    }
    else if(hcint.b.chhltd)
    {
        MASK_HOST_INT_CHH(num);

        if(pdev->host.HC_Status[num] == HC_XFRC)
        {
            pdev->host.URB_State[num] = URB_DONE;

            if(hcchar.b.eptype == EP_TYPE_BULK)
            {
                pdev->host.hc[num].toggle_out ^= 1;
            }
        }
        else if(pdev->host.HC_Status[num] == HC_NAK)
        {
            pdev->host.URB_State[num] = URB_NOTREADY;
        }
        else if(pdev->host.HC_Status[num] == HC_NYET)
        {
            if(pdev->host.hc[num].do_ping == 1)
            {
                USB_OTG_HC_DoPing(pdev, num);
            }

            pdev->host.URB_State[num] = URB_NOTREADY;
        }
        else if(pdev->host.HC_Status[num] == HC_STALL)
        {
            pdev->host.URB_State[num] = URB_STALL;
        }
        else if(pdev->host.HC_Status[num] == HC_XACTERR)
        {
            if(pdev->host.ErrCnt[num] == 3)
            {
                pdev->host.URB_State[num] = URB_ERROR;
                pdev->host.ErrCnt[num] = 0;
            }
        }

        CLEAR_HC_INT(hcreg, chhltd);
    }

    return 1;
}
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma optimize = none
#endif /* __CC_ARM */
/**
* @brief  USB_OTG_USBH_handle_hc_n_In_ISR
*         Handles interrupt for a specific Host Channel
* @param  pdev: Selected device
* @param  hc_num: Channel number
* @retval status
*/
uint32_t USB_OTG_USBH_handle_hc_n_In_ISR(USB_OTG_CORE_HANDLE *pdev, uint32_t num)
{
    USB_OTG_HCINTn_TypeDef     hcint;
    USB_OTG_HCINTMSK_TypeDef  hcintmsk;
    USB_OTG_HCCHAR_TypeDef     hcchar;
    USB_OTG_HCTSIZn_TypeDef  hctsiz;
    USB_OTG_HC_REGS *hcreg;
    hcreg = pdev->regs.HC_REGS[num];
    hcint.d32 = USB_OTG_READ_REG32(&hcreg->HCINT);
    hcintmsk.d32 = USB_OTG_READ_REG32(&hcreg->HCINTMSK);
    hcint.d32 = hcint.d32 & hcintmsk.d32;
    hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[num]->HCCHAR);
    hcintmsk.d32 = 0;

    if(hcint.b.ahberr)
    {
        CLEAR_HC_INT(hcreg, ahberr);
        UNMASK_HOST_INT_CHH(num);
    }
    else if(hcint.b.ack)
    {
        CLEAR_HC_INT(hcreg, ack);
    }
    else if(hcint.b.stall)
    {
        UNMASK_HOST_INT_CHH(num);
        pdev->host.HC_Status[num] = HC_STALL;
        CLEAR_HC_INT(hcreg, nak);    /* Clear the NAK Condition */
        CLEAR_HC_INT(hcreg, stall);  /* Clear the STALL Condition */
        hcint.b.nak = 0;           /* NOTE: When there is a 'stall', reset also nak,
                                  else, the pdev->host.HC_Status = HC_STALL
    will be overwritten by 'nak' in code below */
        USB_OTG_HC_Halt(pdev, num);
    }
    else if(hcint.b.datatglerr)
    {
        UNMASK_HOST_INT_CHH(num);
        USB_OTG_HC_Halt(pdev, num);
        CLEAR_HC_INT(hcreg, nak);
        pdev->host.HC_Status[num] = HC_DATATGLERR;
        CLEAR_HC_INT(hcreg, datatglerr);
    }

    if(hcint.b.frmovrun)
    {
        UNMASK_HOST_INT_CHH(num);
        USB_OTG_HC_Halt(pdev, num);
        CLEAR_HC_INT(hcreg, frmovrun);
    }
    else if(hcint.b.xfercompl)
    {
        if(pdev->cfg.dma_enable == 1)
        {
            hctsiz.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[num]->HCTSIZ);
            pdev->host.XferCnt[num] =  pdev->host.hc[num].xfer_len - hctsiz.b.xfersize;
        }

        pdev->host.HC_Status[num] = HC_XFRC;
        pdev->host.ErrCnt [num] = 0;
        CLEAR_HC_INT(hcreg, xfercompl);

        if((hcchar.b.eptype == EP_TYPE_CTRL) ||
                (hcchar.b.eptype == EP_TYPE_BULK))
        {
            UNMASK_HOST_INT_CHH(num);
            USB_OTG_HC_Halt(pdev, num);
            CLEAR_HC_INT(hcreg, nak);
            pdev->host.hc[num].toggle_in ^= 1;
        }
        else if(hcchar.b.eptype == EP_TYPE_INTR)
        {
            hcchar.b.oddfrm  = 1;
            USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[num]->HCCHAR, hcchar.d32);
            pdev->host.URB_State[num] = URB_DONE;
        }
    }
    else if(hcint.b.chhltd)
    {
        MASK_HOST_INT_CHH(num);

        if(pdev->host.HC_Status[num] == HC_XFRC)
        {
            pdev->host.URB_State[num] = URB_DONE;
        }
        else if(pdev->host.HC_Status[num] == HC_STALL)
        {
            pdev->host.URB_State[num] = URB_STALL;
        }
        else if((pdev->host.HC_Status[num] == HC_XACTERR) ||
                (pdev->host.HC_Status[num] == HC_DATATGLERR))
        {
            pdev->host.ErrCnt[num] = 0;
            pdev->host.URB_State[num] = URB_ERROR;
        }
        else if(hcchar.b.eptype == EP_TYPE_INTR)
        {
            pdev->host.hc[num].toggle_in ^= 1;
        }

        CLEAR_HC_INT(hcreg, chhltd);
    }
    else if(hcint.b.xacterr)
    {
        UNMASK_HOST_INT_CHH(num);
        pdev->host.ErrCnt[num] ++;
        pdev->host.HC_Status[num] = HC_XACTERR;
        USB_OTG_HC_Halt(pdev, num);
        CLEAR_HC_INT(hcreg, xacterr);
    }
    else if(hcint.b.nak)
    {
        if(hcchar.b.eptype == EP_TYPE_INTR)
        {
            UNMASK_HOST_INT_CHH(num);
            USB_OTG_HC_Halt(pdev, num);
        }
        else if((hcchar.b.eptype == EP_TYPE_CTRL) ||
                (hcchar.b.eptype == EP_TYPE_BULK))
        {
            /* re-activate the channel  */
            hcchar.b.chen = 1;
            hcchar.b.chdis = 0;
            USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[num]->HCCHAR, hcchar.d32);
        }

        pdev->host.HC_Status[num] = HC_NAK;
        CLEAR_HC_INT(hcreg, nak);
    }

    return 1;
}

/**
* @brief  USB_OTG_USBH_handle_rx_qlvl_ISR
*         Handles the Rx Status Queue Level Interrupt
* @param  pdev: Selected device
* @retval status
*/
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma optimize = none
#endif /* __CC_ARM */
static uint32_t USB_OTG_USBH_handle_rx_qlvl_ISR(USB_OTG_CORE_HANDLE *pdev)
{
    USB_OTG_GRXFSTS_TypeDef       grxsts;
    USB_OTG_GINTMSK_TypeDef       intmsk;
    USB_OTG_HCTSIZn_TypeDef       hctsiz;
    USB_OTG_HCCHAR_TypeDef        hcchar;
    __IO uint8_t                  channelnum = 0;
    uint32_t                      count;
    /* Disable the Rx Status Queue Level interrupt */
    intmsk.d32 = 0;
    intmsk.b.rxstsqlvl = 1;
    USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, intmsk.d32, 0);
    grxsts.d32 = USB_OTG_READ_REG32(&pdev->regs.GREGS->GRXSTSP);
    channelnum = grxsts.b.chnum;
    hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[channelnum]->HCCHAR);

    switch(grxsts.b.pktsts)
    {
        case GRXSTS_PKTSTS_IN:

            /* Read the data into the host buffer. */
            if((grxsts.b.bcnt > 0) && (pdev->host.hc[channelnum].xfer_buff != (void *)0))
            {
                USB_OTG_ReadPacket(pdev, pdev->host.hc[channelnum].xfer_buff, grxsts.b.bcnt);
                /*manage multiple Xfer */
                pdev->host.hc[grxsts.b.chnum].xfer_buff += grxsts.b.bcnt;
                pdev->host.hc[grxsts.b.chnum].xfer_count  += grxsts.b.bcnt;
                count = pdev->host.hc[channelnum].xfer_count;
                pdev->host.XferCnt[channelnum]  = count;
                hctsiz.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[channelnum]->HCTSIZ);

                if(hctsiz.b.pktcnt > 0)
                {
                    /* re-activate the channel when more packets are expected */
                    hcchar.b.chen = 1;
                    hcchar.b.chdis = 0;
                    USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[channelnum]->HCCHAR, hcchar.d32);
                }
            }

            break;

        case GRXSTS_PKTSTS_IN_XFER_COMP:
        case GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
        case GRXSTS_PKTSTS_CH_HALTED:
        default:
            break;
    }

    /* Enable the Rx Status Queue Level interrupt */
    intmsk.b.rxstsqlvl = 1;
    USB_OTG_MODIFY_REG32(&pdev->regs.GREGS->GINTMSK, 0, intmsk.d32);
    return 1;
}

/**
* @brief  USB_OTG_USBH_handle_IncompletePeriodicXfer_ISR
*         Handles the incomplete Periodic transfer Interrupt
* @param  pdev: Selected device
* @retval status
*/
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma optimize = none
#endif /* __CC_ARM */
static uint32_t USB_OTG_USBH_handle_IncompletePeriodicXfer_ISR(USB_OTG_CORE_HANDLE *pdev)
{
    USB_OTG_GINTSTS_TypeDef       gintsts;
    USB_OTG_HCCHAR_TypeDef        hcchar;
    hcchar.d32 = USB_OTG_READ_REG32(&pdev->regs.HC_REGS[0]->HCCHAR);
    hcchar.b.chen = 1;
    hcchar.b.chdis = 1;
    USB_OTG_WRITE_REG32(&pdev->regs.HC_REGS[0]->HCCHAR, hcchar.d32);
    gintsts.d32 = 0;
    /* Clear interrupt */
    gintsts.b.incomplisoout = 1;
    USB_OTG_WRITE_REG32(&pdev->regs.GREGS->GINTSTS, gintsts.d32);
    return 1;
}

/**
* @}
*/

/**
* @}
*/

/**
* @}
*/

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

